Skip to contentMethod: isReadOnly(ELContext, Object, Object)
1: /*
2: * Copyright (c) 1997, 2020 Oracle and/or its affiliates and others.
3: * All rights reserved.
4: * Copyright 2004 The Apache Software Foundation
5: *
6: * Licensed under the Apache License, Version 2.0 (the "License");
7: * you may not use this file except in compliance with the License.
8: * You may obtain a copy of the License at
9: *
10: * http://www.apache.org/licenses/LICENSE-2.0
11: *
12: * Unless required by applicable law or agreed to in writing, software
13: * distributed under the License is distributed on an "AS IS" BASIS,
14: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15: * See the License for the specific language governing permissions and
16: * limitations under the License.
17: */
18:
19: package jakarta.servlet.jsp.el;
20:
21: import java.beans.FeatureDescriptor;
22: import java.util.Iterator;
23: import java.util.ArrayList;
24: import java.util.Enumeration;
25:
26: import jakarta.servlet.jsp.PageContext;
27: import jakarta.servlet.jsp.JspContext;
28:
29: import jakarta.el.ELContext;
30: import jakarta.el.ELResolver;
31: import jakarta.el.ELException;
32:
33: /**
34: * Defines variable resolution behavior for scoped attributes.
35: *
36: * <p>
37: * This resolver handles variable resolutions where <code>base</code> is <code>null</code>. It searches
38: * <code>PageContext.findAttribute()</code> for a matching attribute. If not found in the case of
39: * <code>setValue</code>, it will create a new attribute in the page scope with the given name.
40: * </p>
41: *
42: * @see jakarta.el.ELResolver
43: * @since JSP 2.1
44: */
45: public class ScopedAttributeELResolver extends ELResolver {
46:
47: /**
48: * If the base object is <code>null</code>, searches the page, request, session and application scopes for an
49: * attribute with the given name and returns it if an attribute exists with the current name.
50: *
51: * <p>
52: * The <code>propertyResolved</code> property of the <code>ELContext</code> object must be set to <code>true</code>
53: * by this resolver before returning if a scoped attribute is matched. If this property is not <code>true</code>
54: * after this method is called, the caller should ignore the return value.
55: * </p>
56: *
57: * @param context The context of this evaluation.
58: * @param base Only <code>null</code> is handled by this resolver. Other values will result in an immediate
59: * return.
60: * @param property The name of the scoped attribute to resolve.
61: * @return If the <code>propertyResolved</code> property of <code>ELContext</code> was set to <code>true</code>,
62: * then the scoped attribute; otherwise undefined.
63: * @throws NullPointerException if context is <code>null</code>
64: * @throws ELException if an exception was thrown while performing the property or variable resolution. The
65: * thrown exception must be included as the cause property of this exception, if
66: * available.
67: */
68: @Override
69: public Object getValue(ELContext context, Object base, Object property) {
70:
71: if (context == null) {
72: throw new NullPointerException();
73: }
74:
75: if (base == null) {
76: if (property instanceof String) {
77: String attribute = (String) property;
78: PageContext ctxt = (PageContext) context.getContext(JspContext.class);
79: Object value = ctxt.findAttribute(attribute);
80: if (value != null) {
81: context.setPropertyResolved(true);
82: }
83: return value;
84: }
85: }
86: return null;
87: }
88:
89: /**
90: * If the base object is <code>null</code>, returns <code>Object.class</code> to indicate that any type is valid to
91: * set for a scoped attribute.
92: *
93: * <p>
94: * The <code>propertyResolved</code> property of the <code>ELContext</code> object must be set to <code>true</code>
95: * by this resolver before returning if base is <code>null</code>. If this property is not <code>true</code> after
96: * this method is called, the caller should ignore the return value.
97: * </p>
98: *
99: * @param context The context of this evaluation.
100: * @param base Only <code>null</code> is handled by this resolver. Other values will result in an immediate
101: * return.
102: * @param property The name of the scoped attribute to resolve.
103: * @return If the <code>propertyResolved</code> property of <code>ELContext</code> was set to <code>true</code>,
104: * then <code>Object.class</code> otherwise undefined.
105: * @throws NullPointerException if context is <code>null</code>
106: * @throws ELException if an exception was thrown while performing the property or variable resolution. The
107: * thrown exception must be included as the cause property of this exception, if
108: * available.
109: */
110: @Override
111: public Class<Object> getType(ELContext context, Object base, Object property) {
112:
113: if (context == null) {
114: throw new NullPointerException();
115: }
116:
117: if (base == null) {
118: context.setPropertyResolved(true);
119: return Object.class;
120: }
121: return null;
122: }
123:
124: /**
125: * If the base object is <code>null</code>, sets an existing scoped attribute to the new value, or creates a new
126: * scoped attribute if one does not exist by this name.
127: *
128: * <p>
129: * If the provided attribute name matches the key of an attribute in page scope, request scope, session scope, or
130: * application scope, the corresponding attribute value will be replaced by the provided value. Otherwise, a new
131: * page scope attribute will be created with the given name and value.
132: * </p>
133: *
134: * <p>
135: * The <code>propertyResolved</code> property of the <code>ELContext</code> object must be set to <code>true</code>
136: * by this resolver before returning if base is <code>null</code>. If this property is not <code>true</code> after
137: * this method is called, the caller should ignore the return value.
138: * </p>
139: *
140: * @param context The context of this evaluation.
141: * @param base Only <code>null</code> is handled by this resolver. Other values will result in an immediate
142: * return.
143: * @param property The name of the scoped attribute to set.
144: * @param val The value for the scoped attribute.
145: * @throws NullPointerException if context is <code>null</code>.
146: * @throws ELException if an exception was thrown while performing the property or variable resolution. The
147: * thrown exception must be included as the cause property of this exception, if
148: * available.
149: */
150: @Override
151: public void setValue(ELContext context, Object base, Object property, Object val) {
152: if (context == null) {
153: throw new NullPointerException();
154: }
155:
156: if (base == null) {
157: context.setPropertyResolved(true);
158: if (property instanceof String) {
159: PageContext ctxt = (PageContext) context.getContext(JspContext.class);
160: String attr = (String) property;
161: if (ctxt.getAttribute(attr, PageContext.REQUEST_SCOPE) != null)
162: ctxt.setAttribute(attr, val, PageContext.REQUEST_SCOPE);
163: else if (ctxt.getAttribute(attr, PageContext.SESSION_SCOPE) != null)
164: ctxt.setAttribute(attr, val, PageContext.SESSION_SCOPE);
165: else if (ctxt.getAttribute(attr, PageContext.APPLICATION_SCOPE) != null)
166: ctxt.setAttribute(attr, val, PageContext.APPLICATION_SCOPE);
167: else {
168: ctxt.setAttribute(attr, val, PageContext.PAGE_SCOPE);
169: }
170: }
171: }
172: }
173:
174: /**
175: * If the base object is <code>null</code>, returns <code>false</code> to indicate that scoped attributes are never
176: * read-only.
177: *
178: * <p>
179: * The <code>propertyResolved</code> property of the <code>ELContext</code> object must be set to <code>true</code>
180: * by this resolver before returning if base is <code>null</code>. If this property is not <code>true</code> after
181: * this method is called, the caller should ignore the return value.
182: * </p>
183: *
184: * @param context The context of this evaluation.
185: * @param base Only <code>null</code> is handled by this resolver. Other values will result in an immediate
186: * return.
187: * @param property The name of the scoped attribute.
188: * @return If the <code>propertyResolved</code> property of <code>ELContext</code> was set to <code>true</code>,
189: * then <code>false</code> otherwise undefined.
190: * @throws NullPointerException if context is <code>null</code>.
191: * @throws ELException if an exception was thrown while performing the property or variable resolution. The
192: * thrown exception must be included as the cause property of this exception, if
193: * available.
194: */
195: @Override
196: public boolean isReadOnly(ELContext context, Object base, Object property) {
197:• if (context == null) {
198: throw new NullPointerException();
199: }
200:
201:• if (base == null) {
202: context.setPropertyResolved(true);
203: }
204: return false;
205: }
206:
207: /**
208: * If the base object is <code>null</code>, returns an <code>Iterator</code> containing
209: * <code>FeatureDescriptor</code> objects with information about each scoped attribute resolved by this resolver.
210: * Otherwise, returns <code>null</code>.
211: *
212: * <p>
213: * The <code>Iterator</code> returned must contain one instance of {@link java.beans.FeatureDescriptor} for each
214: * scoped attribute found in any scope. Each info object contains information about a single scoped attribute, and
215: * is initialized as follows:
216: * </p>
217: *
218: * <dl>
219: * <dt>displayName</dt><dd>- The name of the scoped attribute.</dd>
220: * <dt>name</dt><dd>- Same as displayName property.</dd>
221: * <dt>shortDescription</dt><dd>- A suitable description for the scoped attribute. Should include the attribute's current
222: * scope (page, request, session, application). Will vary by implementation.</dd>
223: * <dt>expert</dt><dd>- <code>false</code></dd>
224: * <dt>hidden</dt><dd>- <code>false</code></dd>
225: * <dt>preferred</dt><dd>- <code>true</code></dd>
226: * </dl>
227: * In addition, the following named attributes must be set in the returned <code>FeatureDescriptor</code>s:
228: * <dl>
229: * <dt>{@link ELResolver#TYPE}</dt><dd>- The current runtime type of the scoped attribute.</dd>
230: * <dt>{@link ELResolver#RESOLVABLE_AT_DESIGN_TIME}</dt><dd>- <code>true</code>.</dd>
231: * </dl>
232: *
233: * @param context The context of this evaluation.
234: * @param base Only <code>null</code> is handled by this resolver. Other values will result in a
235: * <code>null</code> return value.
236: * @return An <code>Iterator</code> containing one <code>FeatureDescriptor</code> object for each scoped attribute,
237: * or <code>null</code> if <code>base</code> is not <code>null</code>.
238: *
239: * @deprecated This method is deprecated as of EL 5.0 and will be removed in EL 6.0 (Jakarta EE 11). Therefore it
240: * will be removed here in JSP 4.0.
241: */
242: @Deprecated(forRemoval = true, since = "JSP 3.1")
243: @Override
244: public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base) {
245: Enumeration<String> attrs;
246: ArrayList<FeatureDescriptor> list = new ArrayList<>();
247: PageContext ctxt = (PageContext) context.getContext(JspContext.class);
248:
249: attrs = ctxt.getAttributeNamesInScope(PageContext.PAGE_SCOPE);
250: while (attrs.hasMoreElements()) {
251: String name = attrs.nextElement();
252: Object value = ctxt.getAttribute(name, PageContext.PAGE_SCOPE);
253: FeatureDescriptor descriptor = new FeatureDescriptor();
254: descriptor.setName(name);
255: descriptor.setDisplayName(name);
256: descriptor.setShortDescription("page scope attribute");
257: descriptor.setExpert(false);
258: descriptor.setHidden(false);
259: descriptor.setPreferred(true);
260: descriptor.setValue("type", value.getClass());
261: descriptor.setValue("resolvableAtDesignTime", Boolean.TRUE);
262: list.add(descriptor);
263: }
264:
265: attrs = ctxt.getAttributeNamesInScope(PageContext.REQUEST_SCOPE);
266: while (attrs.hasMoreElements()) {
267: String name = attrs.nextElement();
268: Object value = ctxt.getAttribute(name, PageContext.REQUEST_SCOPE);
269: FeatureDescriptor descriptor = new FeatureDescriptor();
270: descriptor.setName(name);
271: descriptor.setDisplayName(name);
272: descriptor.setShortDescription("request scope attribute");
273: descriptor.setExpert(false);
274: descriptor.setHidden(false);
275: descriptor.setPreferred(true);
276: descriptor.setValue("type", value.getClass());
277: descriptor.setValue("resolvableAtDesignTime", Boolean.TRUE);
278: list.add(descriptor);
279: }
280:
281: attrs = ctxt.getAttributeNamesInScope(PageContext.SESSION_SCOPE);
282: while (attrs.hasMoreElements()) {
283: String name = attrs.nextElement();
284: Object value = ctxt.getAttribute(name, PageContext.SESSION_SCOPE);
285: FeatureDescriptor descriptor = new FeatureDescriptor();
286: descriptor.setName(name);
287: descriptor.setDisplayName(name);
288: descriptor.setShortDescription("session scope attribute");
289: descriptor.setExpert(false);
290: descriptor.setHidden(false);
291: descriptor.setPreferred(true);
292: descriptor.setValue("type", value.getClass());
293: descriptor.setValue("resolvableAtDesignTime", Boolean.TRUE);
294: list.add(descriptor);
295: }
296:
297: attrs = ctxt.getAttributeNamesInScope(PageContext.APPLICATION_SCOPE);
298: while (attrs.hasMoreElements()) {
299: String name = attrs.nextElement();
300: Object value = ctxt.getAttribute(name, PageContext.APPLICATION_SCOPE);
301: FeatureDescriptor descriptor = new FeatureDescriptor();
302: descriptor.setName(name);
303: descriptor.setDisplayName(name);
304: descriptor.setShortDescription("application scope attribute");
305: descriptor.setExpert(false);
306: descriptor.setHidden(false);
307: descriptor.setPreferred(true);
308: descriptor.setValue("type", value.getClass());
309: descriptor.setValue("resolvableAtDesignTime", Boolean.TRUE);
310: list.add(descriptor);
311: }
312: return list.iterator();
313: }
314:
315: /**
316: * If the base object is <code>null</code>, returns <code>String.class</code>. Otherwise, returns <code>null</code>.
317: *
318: * @param context The context of this evaluation.
319: * @param base Only <code>null</code> is handled by this resolver. Other values will result in a
320: * <code>null</code> return value.
321: * @return <code>null</code> if base is not <code>null</code> otherwise <code>String.class</code>.
322: */
323: @Override
324: public Class<String> getCommonPropertyType(ELContext context, Object base) {
325: if (base == null) {
326: return String.class;
327: }
328: return null;
329: }
330:
331: }